/*
 * Copyright (c) 2018 - 2028. www.vtuzx.com Inc. All Rights Reserved
 */
package com.vtuzx.kingdee.xqc_api.service.impl;

import com.vtuzx.core.VtuzxException;
import com.vtuzx.core.bean.dto.VtuzxFile;
import com.vtuzx.core.bean.dto.VtuzxMap;
import com.vtuzx.core.bean.dto.VtuzxPage;
import com.vtuzx.core.bean.dto.VtuzxToken;
import com.vtuzx.core.constant.IVtuzxConst;
import com.vtuzx.core.file.excel.VtuzxExcel;
import com.vtuzx.core.file.excel.VtuzxExcelCell;
import com.vtuzx.core.file.excel.VtuzxExcelSheet;
import com.vtuzx.core.utils.VtuzxUtil;
import com.vtuzx.fast.dao.setting.DictDao;
import com.vtuzx.fast.utils.FastUtil;
import com.vtuzx.kingdee.xqc_api.service.IXqcInventoryService;
import com.vtuzx.kingdee.xqc_api.service.IXqcSaleService;
import com.vtuzx.kingdee.xqc_api.service.IXqcSyncKingdeeOrderService;
import com.vtuzx.kingdee.xqc_core.constant.BillEvent;
import com.vtuzx.kingdee.xqc_core.constant.BillStatus;
import com.vtuzx.kingdee.xqc_core.constant.BillType;
import com.vtuzx.kingdee.xqc_core.constant.IXqcConst;
import com.vtuzx.kingdee.xqc_core.dao.*;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.print.Doc;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

import static com.vtuzx.kingdee.xqc_api.service.impl.XqcAllocationServiceImpl.list2Map;

/**
 * 采购服务
 */
@Service
public class XqcSaleServiceImpl implements IXqcSaleService {
    /** Logger */
    private static final Logger _logger = LoggerFactory.getLogger(XqcSaleServiceImpl.class);

    @Autowired
    private SaleOutDao saleOutDao;

    @Autowired
    private SaleOutDetailDao saleOutDetailDao;

    @Autowired
    private SaleOutDetailBoxDao saleOutDetailBoxDao;

    @Autowired
    private InventoryDetailDao inventoryDetailDao;

    @Autowired
    private InventoryDao inventoryDao;

    @Autowired
    private IXqcInventoryService inventoryService;

    @Autowired
    private MaterialDao materialDao;

    @Autowired
    private XqcInventoryServiceImpl xqcInventoryService;

    @Autowired
    private SaleStoreDao saleStoreDao;

    @Autowired
    private SaleStoreDetailDao saleStoreDetailDao;

    @Autowired
    private SaleStoreSaleDao saleStoreSaleDao;

    @Autowired
    private SaleStoreSaleDetailDao saleStoreSaleDetailDao;

    @Autowired
    private DistributorDao distributorDao;

    @Autowired
    private DistributorDetailDao distributorDetailDao;

    @Autowired
    private IXqcSyncKingdeeOrderService syncKingdeeOrderService;

    @Autowired
    private DictDao dictDao;

    public VtuzxMap getOptions(Map<String, Object> param) {
        List<String> keys = VtuzxUtil.getObject(param, "keys");
        Iterator<Document> dictList = dictDao.findList(Criteria.where("key").in(keys).and("effect").is(true), null, 0, 0);
        VtuzxMap retMap = new VtuzxMap();
        while (dictList.hasNext()) {
            Document dict = dictList.next();
            List<VtuzxMap> options = new ArrayList<>();
            String key = VtuzxUtil.getObject(dict, "key");
            retMap.put(key, options);
            List<Document> dbs = VtuzxUtil.getObject(dict, "details");
            if (dbs != null) {
                sortDictDetails(dbs);
                for (Document detail : dbs) {
                    if (VtuzxUtil.getBoolean(detail, "effect")) {
                        VtuzxMap dictDetail = new VtuzxMap("key", VtuzxUtil.getString(detail, "key"))
                                .append("name", VtuzxUtil.getString(detail, "name"))
                                .append("remark", VtuzxUtil.getString(detail, "remark"));
                        options.add(dictDetail);
                    }
                }
            }
        }
        return retMap;
    }

    private void sortDictDetails(List<Document> details) {
        details.sort((o1, o2) -> {
            int sort1 = VtuzxUtil.getInt(o1, "sort");
            String key1 = VtuzxUtil.getString(o1, "key");
            int sort2 = VtuzxUtil.getInt(o2, "sort");
            String key2 = VtuzxUtil.getString(o2, "key");
            return sort1 == sort2 ? key1.compareTo(key2) : sort1 - sort2;
        });
    }

    @Override
    public VtuzxMap saveUserSaleOut(ObjectId _userId, String userName, Map<String, Object> param) throws VtuzxException {
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String type = VtuzxUtil.getString(param, "type");
        String billNo = IXqcConst.createBillNo(BillType.XSCK);
        String pickType = VtuzxUtil.getString(param,"pickType");
//        List<String> boxNoList = new ArrayList<>();
//        List<String> materialRowIdList = new ArrayList<>();
        List<ObjectId> detailIdList = new ArrayList<>();
        Criteria opCond = Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true);
        if ("sale".equals(type)) {
            opCond.and("type").is(type);
        }
        Iterator<Document> detailItr = saleOutDetailDao.findList(opCond, null, 0, 0);
        int boxCount = 0;
        double count = 0d;
        while(detailItr.hasNext()) {
            Document detail = detailItr.next();
            ObjectId id = VtuzxUtil.getObject(detail, IVtuzxConst.Key__id);
            boxCount += VtuzxUtil.getDouble(detail, "boxCount");
            count += VtuzxUtil.getDouble(detail, "count");
            detailIdList.add(id);
        }

        VtuzxMap boxIdMap = new VtuzxMap();
        Iterator<Document> boxItr = saleOutDetailBoxDao.findList(Criteria.where("_detailId").in(detailIdList), null, 0, 0);
        while (boxItr.hasNext()) {
            Document boxDoc = boxItr.next();
            String boxNo = VtuzxUtil.getString(boxDoc, "boxNo");
            String id = VtuzxUtil.getString(boxDoc, "_detailId");
//            boxNoList.add(boxNo);
            boxIdMap.append(boxNo, id);
        }

//        List<String> outBoxNoList = new ArrayList<>();
//        Iterator<Document> inventoryItr = inventoryDetailDao.findList(Criteria.where("boxNo").in(boxNoList).and("status").is("in"), null, 0, 0);
//        while (inventoryItr.hasNext()) {
//            Document inventoryDoc = inventoryItr.next();
//            String status = VtuzxUtil.getString(inventoryDoc, "status");
//            String boxNo = VtuzxUtil.getString(inventoryDoc, "boxNo");
//            if ("out".equals(status)) {
//                outBoxNoList.add(boxNo);
//                String detailId = VtuzxUtil.getString(boxIdMap, boxNo);
//                materialRowIdList.add(detailId);
//            }
//        }
//        if (outBoxNoList.size() > 0) {
//            return new VtuzxMap("outBoxNo", outBoxNoList).append("idList", materialRowIdList);
//        }

        Document saleOutDoc = new Document("billNo", billNo)
                .append("stockNo", stockNo)
                .append("boxCount", boxCount)
                .append("count", count)
                .append("pickType",pickType)
                .append("status", BillStatus.Save.toString());
        if ("sale".equals(type)) {
            saleOutDoc.append("type", type);
        }
        saleOutDao.insertBill(_userId, userName, saleOutDoc);
        try {
            Document detailUpdateVal = new Document("$set", new Document("billNo", billNo));
            detailUpdateVal.append("$unset", new Document("isTemp", 1));
            saleOutDetailDao.updateManyRedirect(opCond, detailUpdateVal);
            saleOutDetailBoxDao.updateManyRedirect(opCond, detailUpdateVal);
            auditSaleOutOrder(_userId, userName, stockNo, billNo);
        } catch(Exception e) {
            Criteria rollbackCond = Criteria.where("billNo").is(billNo);
            saleOutDao.deleteOne(rollbackCond);
            saleOutDetailDao.updateManyRedirect(rollbackCond,
                    new Document("$set", new Document("isTemp", true)).append("$unset", new Document("billNo", 1)));
            saleOutDetailBoxDao.updateManyRedirect(rollbackCond,
                    new Document("$set", new Document("isTemp", true)).append("$unset", new Document("billNo", 1)));
            throw e;
        }
        return new VtuzxMap("billNo", billNo);
    }


    /**
     * 销售出库审批
     *
     * @param _userId 用户ID
     * @param userName 用户名
     * @param stockNo 仓库编码
     * @param billNo 单据号
     * @throws VtuzxException 异常处理
     */
    public void auditSaleOutOrder(ObjectId _userId, String userName, String stockNo, String billNo) throws VtuzxException {
        Document saleOutDoc = saleOutDao.findOne(Criteria.where("billNo").is(billNo));
        String type = VtuzxUtil.getString(saleOutDoc, "type");
        Criteria getCond = Criteria.where("billNo").is(billNo);

        List<Document> saleOutBoxList = new ArrayList<>();
//        List<String> boxList = new ArrayList<>();
        List<Document> zsBoxList = new ArrayList<>();
        Iterator<Document> boxItr = saleOutDetailBoxDao.findList(getCond, null, 0, 0);
        while (boxItr.hasNext()) {
            Document box = boxItr.next();
//            boxList.add(VtuzxUtil.getString(box, "boxNo"));
            saleOutBoxList.add(box);
        }

//        VtuzxMap boxMap = new VtuzxMap();
//        Iterator<Document> invItr = inventoryDetailDao.findList(Criteria.where("boxNo").in(boxList), null, 0, 0);
//        while (invItr.hasNext()) {
//            Document invDoc = invItr.next();
//            boxMap.append(VtuzxUtil.getString(invDoc, "boxNo"), VtuzxUtil.getDouble(invDoc, "count"));
//        }

        List<String> boxNoList = new ArrayList<>();
        List<VtuzxMap> bcBoxList = new ArrayList<>();
        for (Document doc: saleOutBoxList) {
            String barcodeType = VtuzxUtil.getString(doc, "barcodeType");
            String boxNo = VtuzxUtil.getString(doc, "boxNo");
//            double invCount = VtuzxUtil.getDouble(boxMap, boxNo);
            double count = VtuzxUtil.getDouble(doc, "count");
            boolean isZS = VtuzxUtil.getBoolean(doc, "isZS");
            String traceBack = VtuzxUtil.getString(doc, "traceBack");
            if ("BC".equals(barcodeType)) {
                bcBoxList.add(new VtuzxMap("boxNo", boxNo)
                        .append("count", BigDecimal.valueOf(VtuzxUtil.getDouble(doc, "count")).setScale(2, RoundingMode.HALF_UP).doubleValue())
                        .append("locationNo", VtuzxUtil.getString(doc, "locationNo")));
            } else {
//                if (invCount > count) {
//                VtuzxMap bcBoxMap = new VtuzxMap("boxNo", boxNo)
//                        .append("count", BigDecimal.valueOf(VtuzxUtil.getDouble(doc, "count")).setScale(0, RoundingMode.HALF_UP).intValue())
//                        .append("locationNo", VtuzxUtil.getString(doc, "locationNo"));
                if (isZS) {
                    zsBoxList.add(new Document("traceBack", traceBack).append("boxNo", boxNo));
                } else {
                    boxNoList.add(VtuzxUtil.getString(doc, "boxNo"));
                }
//                } else {
//                    boxNoList.add(boxNo);
//                }
            }
        }
        saleOutDao.audit(_userId, userName, billNo);
        if (!"sale".equals(type)) {
            try {
//                syncKingdeeOrderService.syncSaleOut(_userId, userName, billNo, "pda");
            } catch (Exception e) {
                _logger.info(e.getMessage());
            }
            // 更新即时库存
            try {
                inventoryService.reduceInventory(_userId, userName, BillEvent.Audit, BillType.XSCK, stockNo, billNo, boxNoList, bcBoxList, zsBoxList);
            } catch(Exception e) {
                saleOutDao.unaudit(billNo);
                throw e;
            }
        }
    }

    @Override
    public Object addUserSaleOutMaterialBoxList(ObjectId _userId, String name, String stockNo, List<Map<String, Object>> boxList) throws VtuzxException {
        for(Map<String, Object> box: boxList) {
            String boxNo = VtuzxUtil.getString(box, "boxNo");
            String traceBack = VtuzxUtil.getString(box, "traceBack");
            boolean isZS = VtuzxUtil.getBoolean(box, "isZS");
            int traceBackInCount = 0;
            if (isZS) {
                Document detailDoc = inventoryDetailDao.findOne(Criteria.where("boxNo").is(boxNo));
                List<Document> traceBackList = VtuzxUtil.getObject(detailDoc, "traceBack");
                for (Document traceBackNum: traceBackList) {
                    String status = VtuzxUtil.getString(traceBackNum, "status");
                    if ("in".equals(status)) {
                        traceBackInCount++;
                    }
                }
            } else {
                traceBackInCount++;
            }
            String locationNo = VtuzxUtil.getString(box, "locationNo");
            try{
                VtuzxMap xqcProduceDetail = xqcInventoryService.getMaterialBox(stockNo, locationNo, boxNo);
                List<VtuzxMap> dataList = VtuzxUtil.getObject(xqcProduceDetail, "data");
                for (VtuzxMap data: dataList) {
                    addUserSaleOutMaterialBoxInner(data, _userId, name, stockNo, boxNo, BigDecimal.valueOf(VtuzxUtil.getInt(box, "count") / traceBackInCount).setScale(0, RoundingMode.HALF_UP).intValue(), isZS, traceBack);
                }
            } catch (Exception e) {
//                _logger.info("addUserSaleOutMaterialBoxList error:" + e.getMessage());
                throw new VtuzxException(e.getMessage());
            }
        }
        return null;
    }

    @Override
    public VtuzxMap addUserSaleOutMaterialBox(ObjectId _userId, String userName, String stockNo, String boxNo, int count) throws VtuzxException {
        VtuzxMap xqcProduceDetail = xqcInventoryService.getMaterialBox(stockNo, boxNo);
        ObjectId _detailId = addUserSaleOutMaterialBoxInner(xqcProduceDetail, _userId, userName, stockNo, boxNo, count, false, "");
        Document otherOutDetailDoc = saleOutDetailDao.findById(_detailId);
        return new VtuzxMap("boxCount", VtuzxUtil.getObject(otherOutDetailDoc, "boxCount"))
                .append("count", VtuzxUtil.getObject(otherOutDetailDoc, "count"));

    }

    private ObjectId addUserSaleOutMaterialBoxInner(VtuzxMap xqcProduceDetail, ObjectId _userId, String userName, String stockNo, String boxNoKey, int inputCount, boolean isZS, String traceBack) throws VtuzxException {
        String barcodeType = VtuzxUtil.getString(xqcProduceDetail, "barcodeType");
        String materialNo = VtuzxUtil.getString(xqcProduceDetail, "materialNo");
        String type = VtuzxUtil.getString(xqcProduceDetail, "type");
        double count = inputCount;
        String boxNo;
        if ("BC".equals(barcodeType)) {
            boxNo = boxNoKey;
            String[] boxNoList = boxNoKey.split("|;");
            if (boxNoList.length == 5) {
                boxNo = boxNo.substring(0, boxNo.lastIndexOf("|;"));
                boxNo = boxNo.substring(0, boxNo.lastIndexOf("|;"));
                boxNo = boxNo.substring(0, boxNo.lastIndexOf("|;"));
                boxNo = boxNo + "|;batch";
            }
        } else {
            boxNo = boxNoKey;
            if ("sale".equals(type) || isZS) {
                count = inputCount;
            } else {
                count = VtuzxUtil.getDouble(xqcProduceDetail, "count");
            }
        }
        Criteria criteria = new Criteria();
        criteria.and("boxNo").is(boxNo).and("isTemp").is(true);
        if (isZS) {
            criteria.and("traceBack").in(traceBack);
        }
        Document scanBoxDoc = saleOutDetailBoxDao.findOne(criteria);
        if (scanBoxDoc != null) {
            throw new VtuzxException("箱号已出库，请勿重复添加!");
        }

        String materialNumber = VtuzxUtil.getString(xqcProduceDetail, "materialNo");
        String materialName = VtuzxUtil.getString(xqcProduceDetail, "materialName");
        String materialSpec = VtuzxUtil.getString(xqcProduceDetail, "materialSpec");
        String batchNo = VtuzxUtil.getString(xqcProduceDetail, "batchNo");
        String unit = VtuzxUtil.getString(xqcProduceDetail, "unit");
        String produceDate = VtuzxUtil.getString(xqcProduceDetail, "produceDate");
        double exp = VtuzxUtil.getDouble(xqcProduceDetail, "exp");
        String inStockTime = VtuzxUtil.getString(xqcProduceDetail, "inStockTime");
        String locationNo = VtuzxUtil.getString(xqcProduceDetail, "locationNo");
        Criteria detailCond = Criteria.where("_createUserId").is(_userId);
        detailCond.and("isTemp").is(true);
        detailCond.and("stockNo").is(stockNo);
        detailCond.and("materialNo").is(materialNo);
        detailCond.and("batchNo").is(batchNo);
        detailCond.and("unit").is(unit);
        Document detail = saleOutDetailDao.findOne(detailCond);
        Document updateVal = new Document();

        if (detail == null) {
            updateVal.append("isTemp", true);
            updateVal.append("stockNo", stockNo);
            updateVal.append("materialNo", materialNumber);
            updateVal.append("materialName", materialName);
            updateVal.append("materialSpec", materialSpec);
            updateVal.append("batchNo", batchNo);
            updateVal.append("unit", unit);
            updateVal.append("_createUserId", _userId);
            updateVal.append("createUserName", userName);
            updateVal.append("boxCount", 1);
            if (isZS) {
                Document inventoryDoc = inventoryDetailDao.findOne(Criteria.where("boxNo").is(boxNo));
                Double traceCount = VtuzxUtil.getDouble(inventoryDoc,"traceCount");
                if (!VtuzxUtil.isEmpty(traceCount) && traceCount != 0.0){
                    updateVal.append("count", traceCount);
                } else {
                    updateVal.append("count", 1);
                }

            } else {
                updateVal.append("count", count);
            }
            updateVal.append("produceDate", produceDate);
            updateVal.append("exp", exp);
            updateVal.append("inStockTime", inStockTime);
            if ("sale".equals(type)) {
                updateVal.append("type", "sale");
            }
        } else {
            if (isZS) {
                updateVal = new Document("$inc", new Document("boxCount", 1).append("count", 1));
            } else {
                updateVal = new Document("$inc", new Document("boxCount", 1).append("count", count));
            }
        }
        ObjectId _detailId;
        if (detail == null) {
            _detailId = saleOutDetailDao.insertOne(updateVal);
        } else {
            _detailId = VtuzxUtil.getObject(detail, IVtuzxConst.Key__id);
            saleOutDetailDao.updateByIdRedirect(_detailId, updateVal);
        }

//        Document box = saleOutDetailBoxDao.findOne(Criteria.where("boxNo").is(boxNo).and("isTemp").is(true).and("_createUserId").is(_userId));
//        if (box == null) {
        Document detailBox = new Document();
        detailBox.append("isTemp", true);
        detailBox.append("_detailId", _detailId);
        detailBox.append("boxNo", boxNo);
        detailBox.append("barcodeType", barcodeType);
        detailBox.append("_createUserId", _userId);
        detailBox.append("createUserName", userName);
        detailBox.append("stockNo", stockNo);
        detailBox.append("unit", unit);
        detailBox.append("locationNo", locationNo);
        if ("sale".equals(type)) {
            detailBox.append("type", "sale");
        }
        if (isZS) {
            detailBox.append("traceBack", traceBack);
            detailBox.append("isZS", true);
            detailBox.append("count", 1);
        } else {
            detailBox.append("count", count);
        }
        saleOutDetailBoxDao.insertOne(detailBox);
//        } else {
//            List<String> traceBackList = VtuzxUtil.getObject(box, "traceBack");
//            traceBackList.add(traceBack);
//            saleOutDetailBoxDao.updateOne(Criteria.where("boxNo").is(boxNo).and("isTemp").is(true).and("_createUserId").is(_userId), new Document("traceBack", traceBackList));
//            saleOutDetailBoxDao.updateOneRedirect(Criteria.where("boxNo").is(boxNo).and("isTemp").is(true).and("_createUserId").is(_userId), new Document("$inc", new Document("count", count)).append("$set", new Document("traceBack", traceBackList)));
//            saleOutDetailDao.updateByIdRedirect(_detailId, new Document("$inc", new Document("count", count)));
//        }
        return _detailId;
    }

    @Override
    public VtuzxMap deleteUserSaleOutMaterialBox(ObjectId _userId, String id) {
        Document saleOutDetailBoxDoc = saleOutDetailBoxDao.findOne(Criteria.where("_id").is(FastUtil.convertId(id)));
        ObjectId _detailId = VtuzxUtil.getObject(saleOutDetailBoxDoc, "_detailId");
        saleOutDetailBoxDao.deleteById(FastUtil.convertId(id));
        Iterator<Document> saleOutDetailBoxItr = saleOutDetailBoxDao.findList(Criteria.where("_detailId").is(_detailId), null, 0, 0);
        int boxCount = 0;
        double total = 0;
        while(saleOutDetailBoxItr.hasNext()) {
            Document doc = saleOutDetailBoxItr.next();
            double saleOutDetailBoxCount = VtuzxUtil.getDouble(doc, "count");
            total = saleOutDetailBoxCount + total;
            boxCount++;
        }
        if (boxCount == 0 && total == 0) {
            saleOutDetailDao.deleteById(_detailId);
        } else {
            saleOutDetailDao.updateById(_detailId, new Document("boxCount", boxCount).append("count", total));
        }
        return new VtuzxMap("count", total).append("boxCount", boxCount);
    }

    @Override
    public void deleteUserSaleOutMaterial(ObjectId _userId, String id) {
        saleOutDetailDao.deleteById(FastUtil.convertId(id));
        saleOutDetailBoxDao.deleteMany(Criteria.where("_detailId").is(FastUtil.convertId(id)));
    }

    @Override
    public void deleteUserSaleOut(ObjectId _userId, String stockNo) {
        Criteria cond = Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true);
        saleOutDetailDao.deleteMany(cond);
        saleOutDetailBoxDao.deleteMany(cond);
    }

    @Override
    public VtuzxMap updateUserSaleOutMaterialBox(ObjectId _userId, String stockNo, String materialNo, String boxNo, double count) {
        Criteria cond = Criteria.where("_createUserId").is(_userId).and("boxNo").is(boxNo).and("isTemp").is(true);
        Document detailBoxDoc = saleOutDetailBoxDao.findOne(cond);
        ObjectId _detailId = VtuzxUtil.getObject(detailBoxDoc, "_detailId");
        saleOutDetailBoxDao.updateOne(cond, new Document("count", count));
        Iterator<Document> saleOutDetailBoxItr = saleOutDetailBoxDao.findList(Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true), new Document("stockNo", 1), 0, 0);
        int boxCount = 0;
        double total = 0;
        while(saleOutDetailBoxItr.hasNext()) {
            Document doc = saleOutDetailBoxItr.next();
            double saleOutDetailBoxCount = VtuzxUtil.getDouble(doc, "count");
            total = saleOutDetailBoxCount + total;
            boxCount++;
        }
        saleOutDetailDao.updateById(_detailId, new Document("boxCount", boxCount).append("count", total));
        return new VtuzxMap("count", total).append("boxCount", boxCount);
    }

    @Override
    public VtuzxMap getUserSaleOutMaterial(ObjectId _userId, String stockNo) {
        List<VtuzxMap> saleOutDetailList = new ArrayList<>();
        Iterator<Document> saleOutDetailItr = saleOutDetailDao.findList(Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true), null, 0, 0);
        while (saleOutDetailItr.hasNext()) {
            Document saleOutDetailDoc = saleOutDetailItr.next();
            VtuzxMap saleOutDetailMap = new VtuzxMap(saleOutDetailDoc);
            String id = VtuzxUtil.removeString(saleOutDetailMap, IVtuzxConst.Key__id);
            String createUserId = VtuzxUtil.removeString(saleOutDetailMap, "_createUserId");
            saleOutDetailMap.append("id", id).append("createUserId", createUserId);
            saleOutDetailList.add(saleOutDetailMap);
        }
        return new VtuzxMap(IVtuzxConst.Key_data, saleOutDetailList);
    }

    @Override
    public VtuzxMap getUserSaleOutMaterialBox(ObjectId _userId, String _detailId) {
        List<VtuzxMap> saleOutDetailBoxList = new ArrayList<>();
        Iterator<Document> saleOutDetailBoxItr = saleOutDetailBoxDao.findList(Criteria.where("_createUserId").is(_userId).and("_detailId").is(new ObjectId(_detailId)), null, 0, 0);
        while (saleOutDetailBoxItr.hasNext()) {
            Document saleOutDetailBoxDoc = saleOutDetailBoxItr.next();
            VtuzxMap boxMap = new VtuzxMap(saleOutDetailBoxDoc);
            boxMap.remove(IVtuzxConst.Key_createTime);
            boxMap.remove(IVtuzxConst.Key_updateTime);
            boxMap.remove("_createUserId");
            boxMap.remove("createUserName");
            boxMap.remove("_updateUserId");
            boxMap.remove("updateUserName");
            boxMap.append("id", VtuzxUtil.removeString(boxMap, IVtuzxConst.Key__id));
            saleOutDetailBoxList.add(boxMap);
        }
        return new VtuzxMap(IVtuzxConst.Key_data, saleOutDetailBoxList);
    }

    @Override
    public VtuzxMap getSaleOutBill(ObjectId _userId, Map<String, Object> param, int pageIndex, int pageSize) {
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String billNo = VtuzxUtil.getString(param, "billNo");
        String materialNo = VtuzxUtil.getString(param, "materialNo");
        String batchNo = VtuzxUtil.getString(param, "batchNo");
        String boxNo = VtuzxUtil.getString(param, "boxNo");
        String createUserName = VtuzxUtil.getString(param, "createUserName");
        String type = VtuzxUtil.getString(param, "type");
        List<String> auditTime = VtuzxUtil.getObject(param, "auditTime");
        List<VtuzxMap> dataList = new ArrayList<>();
        Criteria cond = new Criteria();
        if (!VtuzxUtil.isEmpty(stockNo)) {
            cond.and("stockNo").regex(stockNo);
        }
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(type)) {
            cond.and("type").is(type);
        } else {
            cond.and("type").ne("sale");
        }
        if (!VtuzxUtil.isEmpty(createUserName)) {
            String[] splitList = createUserName.split("，");
            if (splitList.length == 1) {
                cond.and("createUserName").regex(createUserName);
            } else {
                List<String> split = new ArrayList<>(Arrays.asList(splitList));//数组转list
                cond.and("createUserName").in(split);
            }
        }
        if (!VtuzxUtil.isEmpty(auditTime)) {
            cond.and("auditTime").gte(VtuzxUtil.parseDate(auditTime.get(0))).lte(VtuzxUtil.parseDate(auditTime.get(1) + " 23:59:59"));
        }
        if (!VtuzxUtil.isEmpty(materialNo) || !VtuzxUtil.isEmpty(batchNo) || !VtuzxUtil.isEmpty(boxNo)) {
            List<String> inBillNoList = new ArrayList<>();
            if (!VtuzxUtil.isEmpty(materialNo) || !VtuzxUtil.isEmpty(batchNo)) {
                Criteria smallCond = new Criteria();
                if (!VtuzxUtil.isEmpty(materialNo)) {
                    smallCond.and("materialNo").is(materialNo);
                }
                if (!VtuzxUtil.isEmpty(batchNo)) {
                    smallCond.and("batchNo").regex(batchNo);
                }
                Iterator<Document> purInDetailItr = saleOutDetailDao.findList(smallCond, null, 0, 0);
                while (purInDetailItr.hasNext()) {
                    Document purInDetailDoc = purInDetailItr.next();
                    String purInBillNo = VtuzxUtil.getString(purInDetailDoc, "billNo");
                    inBillNoList.add(purInBillNo);
                }
            } else {
                Iterator<Document> boxItr = saleOutDetailBoxDao.findList(Criteria.where("boxNo").is(boxNo),null, 0, 0);
                while (boxItr.hasNext()) {
                    Document boxDoc = boxItr.next();
                    inBillNoList.add(VtuzxUtil.getString(boxDoc, "billNo"));
                }
            }

            Iterator<Document> purInItr = saleOutDao.findList(Criteria.where("billNo").in(inBillNoList), null, 0, 0);
            while (purInItr.hasNext()) {
                Document purInDoc = purInItr.next();
                VtuzxMap purInMap = new VtuzxMap(purInDoc);
                purInMap.append("id", VtuzxUtil.removeString(purInMap, IVtuzxConst.Key__id));
                purInMap.append("createTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(purInMap, "createTime")));
                dataList.add(purInMap);
            }
            return new VtuzxMap(IVtuzxConst.Key_data, dataList);
        }
        VtuzxPage page = saleOutDao.page(cond, new Document("createTime", -1), pageIndex, pageSize);
        dataList = page.iterator(doc -> new VtuzxMap("id", VtuzxUtil.getString(doc, IVtuzxConst.Key__id))
                .append("billNo", VtuzxUtil.getString(doc, "billNo"))
                .append("createUserName", VtuzxUtil.getString(doc, "createUserName"))
                .append("_createUserId", VtuzxUtil.getObject(doc, "_createUserId"))
                .append("boxCount", VtuzxUtil.getInt(doc, "boxCount"))
                .append("status", VtuzxUtil.getString(doc, "status"))
                .append("stockNo", VtuzxUtil.getString(doc, "stockNo"))
                .append("auditTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "auditTime")))
                .append("pickType",VtuzxUtil.getString(doc,"pickType"))
                .append("count", VtuzxUtil.getDouble(doc, "count")));
        return new VtuzxMap(IVtuzxConst.Key_total, page.total()).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getSaleOutBillDetail(ObjectId _userId, String stockNo, String billNo) {
        Document saleOutDoc = saleOutDao.findOne(Criteria.where("billNo").is(billNo).and("stockNo").is(stockNo));
        String ckBillNo = VtuzxUtil.getString(saleOutDoc, "billNo");
        String createUserName = VtuzxUtil.getString(saleOutDoc, "createUserName");
        String createTime = VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(saleOutDoc, "createTime"));
        String stock = VtuzxUtil.getString(saleOutDoc, "stockNo");
        double count = VtuzxUtil.getDouble(saleOutDoc, "count");
        int boxCount = VtuzxUtil.getInt(saleOutDoc, "boxCount");
        VtuzxMap header = new VtuzxMap("billNo", ckBillNo)
                .append("createUserName", createUserName)
                .append("createTime", createTime)
                .append("stockNo", stock)
                .append("count", count)
                .append("boxCount", boxCount);

        List<VtuzxMap> dataList = new ArrayList<>();
        Iterator<Document> saleOutDetailItr = saleOutDetailDao.findList(Criteria.where("billNo").is(billNo).and("stockNo").is(stockNo), null, 0, 0);
        while (saleOutDetailItr.hasNext()) {
            Document saleOutDetailDoc = saleOutDetailItr.next();
            VtuzxMap saleOutDetailMap = new VtuzxMap(saleOutDetailDoc);
            saleOutDetailMap.remove("unit");
            String _id = VtuzxUtil.removeString(saleOutDetailMap, IVtuzxConst.Key__id);
            String _createUserId = VtuzxUtil.removeString(saleOutDetailMap, "_createUserId");
            dataList.add(saleOutDetailMap.append("_id", _id).append("_createUserId", _createUserId));
        }
        for (VtuzxMap data: dataList) {
            String materialNo = VtuzxUtil.getString(data, "materialNo");
            Document materialDoc = materialDao.findOne(Criteria.where("fNumber").is(materialNo));
            String fBaseUnitIdFName = VtuzxUtil.getString(materialDoc, "fBaseUnitIdFName");
            data.append("unit", fBaseUnitIdFName);

        }
        return new VtuzxMap("header", header).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getSaleOutBillDetailBox(ObjectId _userId, String _detailId) {
        Criteria cond = Criteria.where("_detailId").is(FastUtil.convertId(_detailId));
        List<VtuzxMap> dataList = new ArrayList<>();
        Iterator<Document> saleOutDetailBoxItr = saleOutDetailBoxDao.findList(cond, null, 0, 0);
        while (saleOutDetailBoxItr.hasNext()) {
            Document saleOutDetailBoxDoc = saleOutDetailBoxItr.next();
            VtuzxMap boxMap = new VtuzxMap(saleOutDetailBoxDoc);
            boxMap.remove(IVtuzxConst.Key_createTime);
            boxMap.remove(IVtuzxConst.Key_updateTime);
            boxMap.remove("_createUserId");
            boxMap.remove("createUserName");
            boxMap.remove("_updateUserId");
            boxMap.remove("updateUserName");
            boxMap.remove("unit");
            boxMap.append("id", VtuzxUtil.removeString(boxMap, IVtuzxConst.Key__id));
            Document detailDoc = saleOutDetailDao.findById(_detailId);
            String materialNo = VtuzxUtil.getString(detailDoc, "materialNo");
            boxMap.append("materialNo", materialNo);
            dataList.add(boxMap);
        }
        for (VtuzxMap data: dataList) {
            String materialNo = VtuzxUtil.getString(data, "materialNo");
            Document materialDoc = materialDao.findOne(Criteria.where("fNumber").is(materialNo));
            String fBaseUnitIdFName = VtuzxUtil.getString(materialDoc, "fBaseUnitIdFName");
            data.append("unit", fBaseUnitIdFName);
        }
        return new VtuzxMap(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public void uploadStoreBill(VtuzxToken token, Map<String, Object> param, List<VtuzxFile> vFileList) throws Exception {
        ObjectId _userId = token.getObject(IVtuzxConst.Key__targetId);
        String name = VtuzxUtil.getString(token, "name");
        File file = vFileList.get(0).file();
        List<VtuzxExcelSheet> sheets = VtuzxExcel.read(file);
        VtuzxExcelSheet sheet0 = sheets.get(0);
        List<Document> dataList = new ArrayList<>();
        for(int i = 1, ii = sheet0.rowSize(); i < ii; i++) {
            String orderDate = sheet0.row(i).cell(0).strCellValue();
            String materialNo = sheet0.row(i).cell(1).strCellValue();
            String materialName = sheet0.row(i).cell(2).strCellValue();
            String prdBigType = sheet0.row(i).cell(3).strCellValue();
            String department = sheet0.row(i).cell(4).strCellValue();
            String count = sheet0.row(i).cell(5).strCellValue();
            String deliverDate = sheet0.row(i).cell(6).strCellValue();
            String materialSpec = sheet0.row(i).cell(7).strCellValue();
            String status = sheet0.row(i).cell(8).strCellValue();
            String billNo = sheet0.row(i).cell(9).strCellValue();
            String channel = sheet0.row(i).cell(10).strCellValue();
            Document dataDoc = new Document("billNo", billNo);
            if ("已批准".equals(status)) {
                dataDoc.append("status", "audit");
            }
            dataDoc.append("department", department);
            dataDoc.append("orderDate", orderDate);
            if ("-".equals(deliverDate)) {
                dataDoc.append("deliverDate", "");
            } else {
                dataDoc.append("deliverDate", deliverDate);
            }
            if ("-".equals(channel)) {
                dataDoc.append("channel", "");
            } else {
                dataDoc.append("channel", channel);
            }
            dataDoc.append("prdBigType", prdBigType);
            dataDoc.append("materialNo", materialNo);
            dataDoc.append("materialName", materialName);
            if ("-".equals(materialSpec)) {
                dataDoc.append("materialSpec", "");
            } else {
                dataDoc.append("materialSpec", materialSpec);
            }
            try {
                count = count.replaceAll(",", "");
                dataDoc.append("count", new BigDecimal(count).doubleValue());
            } catch(Exception e) {
                dataDoc.append("count", 0d);
            }
            dataList.add(dataDoc);
        }

        VtuzxMap arrMap = new VtuzxMap();
        for (Document data: dataList) {
            String billNo = VtuzxUtil.getString(data, "billNo");
            List<Document> arrList = VtuzxUtil.getObject(arrMap, billNo);
            if (arrList == null) {
                List<Document> storageList = new ArrayList<>();
                storageList.add(data);
                arrMap.append(billNo, storageList);
            } else {
                arrList.add(data);
            }
        }


        List<String> billNoList = new ArrayList<>();
        Iterator<Document> saleItr = saleStoreDao.findList(null, null, 0, 0);
        while (saleItr.hasNext()) {
            Document saleDoc = saleItr.next();
            String billNo = VtuzxUtil.getString(saleDoc, "billNo");
            billNoList.add(billNo);
        }


        arrMap.forEach((k, v) -> {
            List<Document> docList = (List<Document>) v;
            int boxCount = 0;
            double sum = 0d;
            Document document = docList.get(0);
            String mainOrderDate = VtuzxUtil.getString(document, "orderDate");
            String deliverDate = VtuzxUtil.getString(document, "deliverDate");
            String mainStatus = VtuzxUtil.getString(document, "status");
            String mainDepartment = VtuzxUtil.getString(document, "department");
            String channel = VtuzxUtil.getString(document, "channel");
            String mainBillNo = VtuzxUtil.getString(document, "billNo");
            List<Document> insertList = new ArrayList<>();
            if (!billNoList.contains(mainBillNo)) {
                for (Document doc: docList) {
                    double count = VtuzxUtil.getDouble(doc, "count");
                    sum += count;
                    boxCount++;
                    String prdBigType = VtuzxUtil.getString(doc, "prdBigType");
                    String materialNo = VtuzxUtil.getString(doc, "materialNo");
                    String materialName = VtuzxUtil.getString(doc, "materialName");
                    String materialSpec = VtuzxUtil.getString(doc, "materialSpec");
                    String department = VtuzxUtil.getString(doc, "department");
                    String orderDate = VtuzxUtil.getString(doc, "orderDate");
                    Document insert = new Document("billNo", mainBillNo)
                            .append("orderDate", orderDate)
                            .append("department", department)
                            .append("materialNo", materialNo)
                            .append("materialName", materialName)
                            .append("materialSpec", materialSpec)
                            .append("prdBigType", prdBigType)
                            .append("count", count)
                            .append("pickCount", 0)
                            .append("surplusCount", count)
                            .append("createUserName", name)
                            .append("createUserId", _userId);
                    insertList.add(insert);
                }
                saleStoreDetailDao.insertMany(insertList);

                Document mainDoc = new Document("billNo", mainBillNo)
                        .append("department", mainDepartment)
                        .append("orderDate", mainOrderDate)
                        .append("channel", channel)
                        .append("deliverDate", deliverDate)
                        .append("status", mainStatus)
                        .append("boxCount", boxCount)
                        .append("count", sum);
                saleStoreDao.insertBill(_userId, name, mainDoc);
            }
        });
    }

    @Override
    public void uploadStoreSaleBill(VtuzxToken token, Map<String, Object> param, List<VtuzxFile> vFileList) throws Exception {
        ObjectId _userId = token.getObject(IVtuzxConst.Key__targetId);
        String name = VtuzxUtil.getString(token, "name");
        File file = vFileList.get(0).file();
        List<VtuzxExcelSheet> sheets = VtuzxExcel.read(file);
        VtuzxExcelSheet sheet0 = sheets.get(0);
        List<Document> dataList = new ArrayList<>();
        for(int i = 1, ii = sheet0.rowSize(); i < ii; i++) {
            String department = sheet0.row(i).cell(0).strCellValue();
            String orderDate = sheet0.row(i).cell(1).strCellValue();
            String memberName = sheet0.row(i).cell(2).strCellValue();
            String memberPhone = sheet0.row(i).cell(3).strCellValue();
            String materialName = sheet0.row(i).cell(4).strCellValue();
            String materialSpec = sheet0.row(i).cell(5).strCellValue();
            String unit = sheet0.row(i).cell(6).strCellValue();
            String count = sheet0.row(i).cell(7).strCellValue();
            String price = sheet0.row(i).cell(8).strCellValue();
            String discount = sheet0.row(i).cell(9).strCellValue();
            String discountCount = sheet0.row(i).cell(10).strCellValue();
            String isLowPrice = sheet0.row(i).cell(11).strCellValue();
            String avePrice = sheet0.row(i).cell(12).strCellValue();
            String isGift = sheet0.row(i).cell(13).strCellValue();
            String giftStatus = sheet0.row(i).cell(14).strCellValue();
            String remark = sheet0.row(i).cell(15).strCellValue();
            String billNo = sheet0.row(i).cell(16).strCellValue();
            String payType = sheet0.row(i).cell(17).strCellValue();
            String isFirstPay = sheet0.row(i).cell(18).strCellValue();
            String billUserName = sheet0.row(i).cell(19).strCellValue();
            String memberUserName = sheet0.row(i).cell(20).strCellValue();
            String prdBigType = sheet0.row(i).cell(21).strCellValue();
            String createChannel = sheet0.row(i).cell(22).strCellValue();
            String materialNo = sheet0.row(i).cell(23).strCellValue();
            String dealDiscount = sheet0.row(i).cell(24).strCellValue();
            String discountPrice = sheet0.row(i).cell(25).strCellValue();
            String commissionPrd = sheet0.row(i).cell(26).strCellValue();
            Document dataDoc = new Document("billNo", billNo);
            dataDoc.append("status", "audit");
            dataDoc.append("department", department);
            dataDoc.append("orderDate", orderDate);
            dataDoc.append("memberName", memberName);
            dataDoc.append("memberPhone", memberPhone);
            dataDoc.append("isGift", isGift);
            dataDoc.append("giftStatus", giftStatus);
            dataDoc.append("remark", remark);
            dataDoc.append("payType", payType);
            dataDoc.append("isFirstPay", isFirstPay);
            dataDoc.append("billUserName", billUserName);
            dataDoc.append("memberUserName", memberUserName);
            dataDoc.append("createChannel", createChannel);
            dataDoc.append("prdBigType", prdBigType);
            dataDoc.append("materialNo", materialNo);
            dataDoc.append("materialName", materialName);
            dataDoc.append("commissionPrd", commissionPrd);
            if ("-".equals(unit)) {
                dataDoc.append("unit", "");
            } else {
                dataDoc.append("unit", unit);
            }
            if ("-".equals(isLowPrice)) {
                dataDoc.append("isLowPrice", "");
            } else {
                dataDoc.append("isLowPrice", isLowPrice);
            }
            if ("-".equals(materialSpec)) {
                dataDoc.append("materialSpec", "");
            } else {
                dataDoc.append("materialSpec", materialSpec);
            }
            try {
                dealDiscount = dealDiscount.replaceAll(",", "");
                dataDoc.append("dealDiscount", new BigDecimal(dealDiscount).doubleValue());
            } catch(Exception e) {
                dataDoc.append("dealDiscount", 0d);
            }
            try {
                discountPrice = discountPrice.replaceAll(",", "");
                dataDoc.append("discountPrice", new BigDecimal(discountPrice).doubleValue());
            } catch(Exception e) {
                dataDoc.append("discountPrice", 0d);
            }
            try {
                discount = discount.replaceAll(",", "");
                dataDoc.append("discount", new BigDecimal(discount).doubleValue());
            } catch(Exception e) {
                dataDoc.append("discount", 0d);
            }
            try {
                avePrice = avePrice.replaceAll(",", "");
                dataDoc.append("avePrice", new BigDecimal(avePrice).doubleValue());
            } catch(Exception e) {
                dataDoc.append("avePrice", 0d);
            }
            try {
                discountCount = discountCount.replaceAll(",", "");
                dataDoc.append("discountCount", new BigDecimal(discountCount).doubleValue());
            } catch(Exception e) {
                dataDoc.append("discountCount", 0d);
            }
            try {
                count = count.replaceAll(",", "");
                dataDoc.append("count", new BigDecimal(count).doubleValue());
            } catch(Exception e) {
                dataDoc.append("count", 0d);
            }
            try {
                price = price.replaceAll(",", "");
                dataDoc.append("price", new BigDecimal(price).doubleValue());
            } catch(Exception e) {
                dataDoc.append("price", 0d);
            }
            dataList.add(dataDoc);
        }

        VtuzxMap arrMap = new VtuzxMap();
        for (Document data: dataList) {
            String billNo = VtuzxUtil.getString(data, "billNo");
            List<Document> arrList = VtuzxUtil.getObject(arrMap, billNo);
            if (arrList == null) {
                List<Document> storageList = new ArrayList<>();
                storageList.add(data);
                arrMap.append(billNo, storageList);
            } else {
                arrList.add(data);
            }
        }

        List<String> billNoList = new ArrayList<>();
        Iterator<Document> saleItr = saleStoreSaleDao.findList(null, null, 0, 0);
        while (saleItr.hasNext()) {
            Document saleDoc = saleItr.next();
            String billNo = VtuzxUtil.getString(saleDoc, "billNo");
            billNoList.add(billNo);
        }


        arrMap.forEach((k, v) -> {
            List<Document> docList = (List<Document>) v;
            int boxCount = 0;
            double sum = 0d;
            Document document = docList.get(0);
            String mainOrderDate = VtuzxUtil.getString(document, "orderDate");
            String mainDepartment = VtuzxUtil.getString(document, "department");
            String memberName = VtuzxUtil.getString(document, "memberName");
            String memberPhone = VtuzxUtil.getString(document, "memberPhone");
            String mainBillNo = VtuzxUtil.getString(document, "billNo");
            String payType = VtuzxUtil.getString(document, "payType");
            String isFirstPay = VtuzxUtil.getString(document, "isFirstPay");
            String billUserName = VtuzxUtil.getString(document, "billUserName");
            String memberUserName = VtuzxUtil.getString(document, "memberUserName");
            String prdBigType = VtuzxUtil.getString(document, "prdBigType");
            String createChannel = VtuzxUtil.getString(document, "createChannel");
            String commissionPrd = VtuzxUtil.getString(document, "commissionPrd");
            List<Document> insertList = new ArrayList<>();
            if (!billNoList.contains(mainBillNo)) {
                for (Document doc: docList) {
                    double count = VtuzxUtil.getDouble(doc, "count");
                    sum += count;
                    boxCount++;
                    String materialNo = VtuzxUtil.getString(doc, "materialNo");
                    String materialName = VtuzxUtil.getString(doc, "materialName");
                    String materialSpec = VtuzxUtil.getString(doc, "materialSpec");
                    String unit = VtuzxUtil.getString(doc, "unit");
                    String department = VtuzxUtil.getString(doc, "department");
                    String orderDate = VtuzxUtil.getString(doc, "orderDate");
                    String isGift = VtuzxUtil.getString(doc, "isGift");
                    String isLowPrice = VtuzxUtil.getString(doc, "isLowPrice");
                    String remark = VtuzxUtil.getString(doc, "remark");
                    String giftStatus = VtuzxUtil.getString(doc, "giftStatus");
                    double price = VtuzxUtil.getDouble(doc, "price");
                    double discount = VtuzxUtil.getDouble(doc, "discount");
                    double discountCount = VtuzxUtil.getDouble(doc, "discountCount");
                    double avePrice = VtuzxUtil.getDouble(doc, "avePrice");
                    double dealDiscount = VtuzxUtil.getDouble(doc, "dealDiscount");
                    double discountPrice = VtuzxUtil.getDouble(doc, "discountPrice");
                    Document insert = new Document("billNo", mainBillNo)
                            .append("orderDate", orderDate)
                            .append("department", department)
                            .append("materialNo", materialNo)
                            .append("materialName", materialName)
                            .append("materialSpec", materialSpec)
                            .append("unit", unit)
                            .append("prdBigType", prdBigType)
                            .append("remark", remark)
                            .append("giftStatus", giftStatus)
                            .append("price", price)
                            .append("discount", discount)
                            .append("discountCount", discountCount)
                            .append("avePrice", avePrice)
                            .append("dealDiscount", dealDiscount)
                            .append("discountPrice", discountPrice)
                            .append("isGift", isGift)
                            .append("isLowPrice", isLowPrice)
                            .append("count", count)
                            .append("pickCount", 0)
                            .append("surplusCount", count)
                            .append("createUserName", name)
                            .append("createUserId", _userId);
                    insertList.add(insert);
                }
                saleStoreSaleDetailDao.insertMany(insertList);

                Document mainDoc = new Document("billNo", mainBillNo)
                        .append("department", mainDepartment)
                        .append("orderDate", mainOrderDate)
                        .append("memberName", memberName)
                        .append("memberPhone", memberPhone)
                        .append("payType", payType)
                        .append("isFirstPay", isFirstPay)
                        .append("billUserName", billUserName)
                        .append("memberUserName", memberUserName)
                        .append("createChannel", createChannel)
                        .append("commissionPrd", commissionPrd)
                        .append("boxCount", boxCount)
                        .append("count", sum);
                saleStoreSaleDao.insertBill(_userId, name, mainDoc);
            }

        });
    }

    @Override
    public VtuzxMap getSaleStoreBill(ObjectId userId, Map<String, Object> param, int pageIndex, int pageSize) {
        String billNo = VtuzxUtil.getString(param, "billNo");
        String createUserName = VtuzxUtil.getString(param, "createUserName");
        List<String> orderDate = VtuzxUtil.getObject(param, "orderDate");
        Criteria cond = new Criteria();
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(createUserName)) {
            cond.and("createUserName").regex(createUserName);
        }
        if (!VtuzxUtil.isEmpty(orderDate)) {
            cond.and("orderDate").gte(VtuzxUtil.parseDate(orderDate.get(0))).lte(VtuzxUtil.parseDate(orderDate.get(1) + " 23:59:59"));
        }
        VtuzxPage page = saleStoreDao.page(cond, new Document("createTime", -1), pageIndex, pageSize);
        List<VtuzxMap> dataList = page.iterator(doc -> new VtuzxMap("id", VtuzxUtil.getString(doc, IVtuzxConst.Key__id))
                .append("billNo", VtuzxUtil.getString(doc, "billNo"))
                .append("createUserName", VtuzxUtil.getString(doc, "createUserName"))
                .append("_createUserId", VtuzxUtil.getObject(doc, "_createUserId"))
                .append("boxCount", VtuzxUtil.getInt(doc, "boxCount"))
                .append("status", VtuzxUtil.getString(doc, "status"))
                .append("department", VtuzxUtil.getString(doc, "department"))
                .append("orderDate", VtuzxUtil.getString(doc, "orderDate"))
                .append("count", VtuzxUtil.getDouble(doc, "count")));
        return new VtuzxMap(IVtuzxConst.Key_total, page.total()).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getSaleStoreBillDetail(ObjectId userId, String billNo) {
        Document saleOutDoc = saleStoreDao.findOne(Criteria.where("billNo").is(billNo));
        String ckBillNo = VtuzxUtil.getString(saleOutDoc, "billNo");
        String createUserName = VtuzxUtil.getString(saleOutDoc, "createUserName");
        String orderDate = VtuzxUtil.getString(saleOutDoc, "orderDate");
        String department = VtuzxUtil.getString(saleOutDoc, "department");
        double count = VtuzxUtil.getDouble(saleOutDoc, "count");
        int boxCount = VtuzxUtil.getInt(saleOutDoc, "boxCount");
        VtuzxMap header = new VtuzxMap("billNo", ckBillNo)
                .append("createUserName", createUserName)
                .append("orderDate", orderDate)
                .append("department", department)
                .append("count", count)
                .append("boxCount", boxCount);

        List<VtuzxMap> dataList = new ArrayList<>();
        Iterator<Document> saleStoreDetailItr = saleStoreDetailDao.findList(Criteria.where("billNo").is(billNo), null, 0, 0);
        while (saleStoreDetailItr.hasNext()) {
            Document saleStoreDetailDoc = saleStoreDetailItr.next();
            VtuzxMap saleStoreDetailMap = new VtuzxMap(saleStoreDetailDoc);
            dataList.add(saleStoreDetailMap);
        }
        return new VtuzxMap("header", header).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public void storeSaleBillOutList(ObjectId userId, String name, List<String> billNoList) throws VtuzxException {
        for (String billNo: billNoList) {
            List<Document> saleStoreList = new ArrayList<>();
            Iterator<Document> saleStoreDetailItr = saleStoreSaleDetailDao.findList(Criteria.where("billNo").is(billNo), null, 0, 0);
            while (saleStoreDetailItr.hasNext()) {
                Document saleStore = saleStoreDetailItr.next();
                saleStoreList.add(saleStore);
            }
            storeSaleBillOutListInner(userId, name, billNo, saleStoreList);
        }
    }
    private void storeSaleBillOutListInner(ObjectId userId, String name, String billNo, List<Document> saleStoreList) throws VtuzxException {
        VtuzxMap optionParam = new VtuzxMap();
        List<String> optionKeys = new ArrayList<>();
        optionKeys.add("allocationStock");
        optionParam.append("keys", optionKeys);

        VtuzxMap optionsMap = getOptions(optionParam);
        List<VtuzxMap> allocationOptions = VtuzxUtil.getObject(optionsMap, "allocationStock");
        VtuzxMap allocationOptionMap = list2Map(allocationOptions, "name");
        VtuzxMap toStockNoMap = VtuzxUtil.getObject(allocationOptionMap, "toStockNo");
        String toStockNoKey = VtuzxUtil.getString(toStockNoMap, "key");
        VtuzxMap toLocationNoMap = VtuzxUtil.getObject(allocationOptionMap, "toLocationNo");
        String toLocationNoKey = VtuzxUtil.getString(toLocationNoMap, "key");

        List<String> materialNoList = new ArrayList<>();
        for (Document sale: saleStoreList) {
            String materialNo = VtuzxUtil.getString(sale, "materialNo");
            materialNoList.add(materialNo);
        }

        List<ObjectId> idList = new ArrayList<>();
        List<Document> invList = new ArrayList<>();
        List<Document> invDetailList = new ArrayList<>();
        Iterator<Document> invItr = inventoryDao.findList(Criteria.where("stockNo").is(toStockNoKey).and("materialNo").in(materialNoList), null, 0, 0);
        while (invItr.hasNext()){
            Document invDoc = invItr.next();
            ObjectId id = VtuzxUtil.getObject(invDoc, "_id");
            invList.add(invDoc);
            idList.add(id);

        }
        Iterator<Document> invDetailItr = inventoryDetailDao.findList(Criteria.where("_inventoryId").in(idList).and("status").is("in"), null, 0, 0);
        while (invDetailItr.hasNext()) {
            Document invDetailDoc = invDetailItr.next();
            invDetailList.add(invDetailDoc);
        }

        VtuzxMap dataMap = new VtuzxMap();
        for (Document inv: invList) {
            ObjectId id = VtuzxUtil.getObject(inv, "_id");
            String materialNo = VtuzxUtil.getString(inv, "materialNo");
            for (Document invDetail: invDetailList) {
                ObjectId detailId = VtuzxUtil.getObject(invDetail, "_inventoryId");
                if (id.equals(detailId)) {
                    List<Document> dataList = VtuzxUtil.getObject(dataMap, materialNo);
                    if (dataList == null) {
                        List<Document> list = new ArrayList<>();
                        list.add(invDetail);
                        dataMap.append(materialNo, list);
                    } else {
                        dataList.add(invDetail);
                    }
                }
            }
        }

        List<VtuzxMap> reduceBoxList = new ArrayList<>();
        List<String> boxNoList = new ArrayList<>();
        for (Document saleStore: saleStoreList) {
            String materialNo = VtuzxUtil.getString(saleStore, "materialNo");
            double count = VtuzxUtil.getDouble(saleStore, "count");
            List<Document> dataList = VtuzxUtil.getObject(dataMap, materialNo);
            if (VtuzxUtil.isEmpty(dataList)) {
                throw new VtuzxException("库存不足，请重新校验库存");
            }
            double nowCount = count;
            for (Document data: dataList) {
                double boxNoCount = VtuzxUtil.getDouble(data, "count");
                int inputCount = 0;
                int IntBoxNoCount = BigDecimal.valueOf(nowCount).setScale(0, RoundingMode.HALF_UP).intValue();
                String boxNo = VtuzxUtil.getString(data, "boxNo");
                String[] boxValues = boxNo.split("\\|\\;");
                if (nowCount >= boxNoCount) {
                    if (boxValues.length == 3) {
                        reduceBoxList.add(new VtuzxMap("boxNo", boxNo).append("count", IntBoxNoCount));
                    } else {
                        boxNoList.add(boxNo);
                    }
                    inputCount = BigDecimal.valueOf(boxNoCount).setScale(0, RoundingMode.HALF_UP).intValue();
                } else {
                    reduceBoxList.add(new VtuzxMap("boxNo", boxNo).append("count", IntBoxNoCount).append("locationNo", toLocationNoKey));
                    inputCount = IntBoxNoCount;
                }
                //加数据

                VtuzxMap xqcProduceDetail = xqcInventoryService.getMaterialBox(toStockNoKey, boxNo);
                List<VtuzxMap> innerList = VtuzxUtil.getObject(xqcProduceDetail, "data");
                for (VtuzxMap inner: innerList) {
                    addUserSaleOutMaterialBoxInner(inner.append("type", "sale"), userId, name, toStockNoKey, boxNo, inputCount, false, "");
                }
                nowCount = nowCount - inputCount;
                if (nowCount <= 0) break;
            }
        }

        Map<String, Object> param = new LinkedHashMap<>();
        param.put("stockNo", toStockNoKey);
        param.put("type", "sale");
        VtuzxMap saleOut = saveUserSaleOut(userId, name, param);
        String saleOutBillNo = VtuzxUtil.getString(saleOut, "billNo");

        inventoryService.reduceInventory(userId, name, BillEvent.Audit, BillType.XSCK, saleOutBillNo, boxNoList, reduceBoxList);

        try {
            syncKingdeeOrderService.syncSaleOut(userId, name, saleOutBillNo, "pda");
        } catch (Exception e) {
            _logger.info(e.getMessage());
        }
    }



    @Override
    public VtuzxMap getSaleStoreSaleBill(ObjectId userId, Map<String, Object> param, int pageIndex, int pageSize) {
        String billNo = VtuzxUtil.getString(param, "billNo");
        String createUserName = VtuzxUtil.getString(param, "createUserName");
        List<String> orderDate = VtuzxUtil.getObject(param, "orderDate");
        Criteria cond = new Criteria();
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(createUserName)) {
            cond.and("createUserName").regex(createUserName);
        }
        if (!VtuzxUtil.isEmpty(orderDate)) {
            cond.and("orderDate").gte(VtuzxUtil.parseDate(orderDate.get(0))).lte(VtuzxUtil.parseDate(orderDate.get(1) + " 23:59:59"));
        }
        VtuzxPage page = saleStoreSaleDao.page(cond, new Document("createTime", -1), pageIndex, pageSize);
        List<VtuzxMap> dataList = page.iterator(doc -> new VtuzxMap("id", VtuzxUtil.getString(doc, IVtuzxConst.Key__id))
                .append("billNo", VtuzxUtil.getString(doc, "billNo"))
                .append("createUserName", VtuzxUtil.getString(doc, "createUserName"))
                .append("_createUserId", VtuzxUtil.getObject(doc, "_createUserId"))
                .append("memberName", VtuzxUtil.getString(doc, "memberName"))
                .append("memberPhone", VtuzxUtil.getString(doc, "memberPhone"))
                .append("payType", VtuzxUtil.getString(doc, "payType"))
                .append("isFirstPay", VtuzxUtil.getString(doc, "isFirstPay"))
                .append("billUserName", VtuzxUtil.getString(doc, "billUserName"))
                .append("memberUserName", VtuzxUtil.getString(doc, "memberUserName"))
                .append("createChannel", VtuzxUtil.getString(doc, "createChannel"))
                .append("commissionPrd", VtuzxUtil.getString(doc, "commissionPrd"))
                .append("department", VtuzxUtil.getString(doc, "department"))
                .append("orderDate", VtuzxUtil.getString(doc, "orderDate"))
                .append("boxCount", VtuzxUtil.getInt(doc, "boxCount"))
                .append("count", VtuzxUtil.getDouble(doc, "count")));
        return new VtuzxMap(IVtuzxConst.Key_total, page.total()).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getSaleStoreSaleBillDetail(ObjectId userId, String billNo) {
        Document saleOutDoc = saleStoreSaleDao.findOne(Criteria.where("billNo").is(billNo));

        List<VtuzxMap> dataList = new ArrayList<>();
        Iterator<Document> saleStoreDetailItr = saleStoreSaleDetailDao.findList(Criteria.where("billNo").is(billNo), null, 0, 0);
        while (saleStoreDetailItr.hasNext()) {
            Document saleStoreDetailDoc = saleStoreDetailItr.next();
            VtuzxMap saleStoreDetailMap = new VtuzxMap(saleStoreDetailDoc);
            dataList.add(saleStoreDetailMap);
        }
        return new VtuzxMap("header", new VtuzxMap(saleOutDoc)).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public void deleteBindTraceBack(ObjectId userId, String boxNo, String traceBack) {
        Document boxDoc = saleOutDetailBoxDao.findOne(Criteria.where("boxNo").is(boxNo).and("isTemp").is(true));
        List<String> traceBackList = VtuzxUtil.getObject(boxDoc, "traceBack");
        traceBackList.remove(traceBack);
        saleOutDetailBoxDao.updateOne(Criteria.where("boxNo").is(boxNo), new Document("traceBack", traceBackList));
    }

    @Override
    public void uploadDistributorBill(VtuzxToken token, Map<String, Object> param, List<VtuzxFile> vFileList) throws Exception {
        ObjectId _userId = token.getObject(IVtuzxConst.Key__targetId);
        String name = VtuzxUtil.getString(token, "name");
        File file = vFileList.get(0).file();
        List<VtuzxExcelSheet> sheets = VtuzxExcel.read(file);
        VtuzxExcelSheet sheet0 = sheets.get(0);
        List<Document> dataList = new ArrayList<>();
        for(int i = 1, ii = sheet0.rowSize(); i < ii; i++) {
            String accountingPeriod = sheet0.row(i).cell(0).strCellValue();
            String distributor = sheet0.row(i).cell(1).strCellValue();
            String prdType = sheet0.row(i).cell(2).strCellValue();
            String sonBigType = sheet0.row(i).cell(3).strCellValue();
            String materialNo = sheet0.row(i).cell(4).strCellValue();
            String materialName = sheet0.row(i).cell(5).strCellValue();
            String materialSpec = sheet0.row(i).cell(6).strCellValue();
            String unit = sheet0.row(i).cell(7).strCellValue();
            String count = sheet0.row(i).cell(8).strCellValue();
            String SumCount = sheet0.row(i).cell(9).strCellValue();
            String money = sheet0.row(i).cell(10).strCellValue();
            String costPrice = sheet0.row(i).cell(11).strCellValue();
            String avgPrice = sheet0.row(i).cell(12).strCellValue();
            String billNo = sheet0.row(i).cell(13).strCellValue();
            String remark = sheet0.row(i).cell(14).strCellValue();
            Document dataDoc = new Document("billNo", billNo);
            dataDoc.append("status", "audit");
            dataDoc.append("accountingPeriod", accountingPeriod);
            dataDoc.append("distributor", distributor);
            dataDoc.append("prdType", prdType);
            dataDoc.append("remark", remark);
            dataDoc.append("materialNo", materialNo);
            if ("-".equals(unit)) {
                dataDoc.append("unit", "");
            } else {
                dataDoc.append("unit", unit);
            }
            if ("-".equals(materialSpec)) {
                dataDoc.append("materialSpec", "");
            } else {
                dataDoc.append("materialSpec", materialSpec);
            }
            if ("-".equals(remark)) {
                dataDoc.append("remark", "");
            } else {
                dataDoc.append("remark", remark);
            }
            if ("-".equals(sonBigType)) {
                dataDoc.append("sonBigType", "");
            } else {
                dataDoc.append("sonBigType", sonBigType);
            }
            if ("-".equals(materialName)) {
                dataDoc.append("materialName", "");
            } else {
                dataDoc.append("materialName", materialName);
            }
            try {
                SumCount = SumCount.replaceAll(",", "");
                dataDoc.append("SumCount", new BigDecimal(SumCount).doubleValue());
            } catch(Exception e) {
                dataDoc.append("SumCount", 0d);
            }
            try {
                money = money.replaceAll(",", "");
                dataDoc.append("money", new BigDecimal(money).doubleValue());
            } catch(Exception e) {
                dataDoc.append("money", 0d);
            }
            try {
                costPrice = costPrice.replaceAll(",", "");
                dataDoc.append("costPrice", new BigDecimal(costPrice).doubleValue());
            } catch(Exception e) {
                dataDoc.append("costPrice", 0d);
            }
            try {
                avgPrice = avgPrice.replaceAll(",", "");
                dataDoc.append("avgPrice", new BigDecimal(avgPrice).doubleValue());
            } catch(Exception e) {
                dataDoc.append("avgPrice", 0d);
            }
            try {
                count = count.replaceAll(",", "");
                dataDoc.append("count", new BigDecimal(count).doubleValue());
            } catch(Exception e) {
                dataDoc.append("count", 0d);
            }
            dataList.add(dataDoc);
        }

        VtuzxMap arrMap = new VtuzxMap();
        for (Document data: dataList) {
            String billNo = VtuzxUtil.getString(data, "billNo");
            List<Document> arrList = VtuzxUtil.getObject(arrMap, billNo);
            if (arrList == null) {
                List<Document> storageList = new ArrayList<>();
                storageList.add(data);
                arrMap.append(billNo, storageList);
            } else {
                arrList.add(data);
            }
        }

        List<String> billNoList = new ArrayList<>();
        Iterator<Document> saleItr = saleStoreSaleDao.findList(null, null, 0, 0);
        while (saleItr.hasNext()) {
            Document saleDoc = saleItr.next();
            String billNo = VtuzxUtil.getString(saleDoc, "billNo");
            billNoList.add(billNo);
        }


        arrMap.forEach((k, v) -> {
            List<Document> docList = (List<Document>) v;
            int boxCount = 0;
            double sum = 0d;
            Document document = docList.get(0);
            String accountingPeriod = VtuzxUtil.getString(document, "accountingPeriod");
            String distributor = VtuzxUtil.getString(document, "distributor");
            String mainBillNo = VtuzxUtil.getString(document, "billNo");
            List<Document> insertList = new ArrayList<>();
            if (!billNoList.contains(mainBillNo)) {
                for (Document doc: docList) {
                    double count = VtuzxUtil.getDouble(doc, "count");
                    sum += count;
                    boxCount++;
                    String materialNo = VtuzxUtil.getString(doc, "materialNo");
                    String materialName = VtuzxUtil.getString(doc, "materialName");
                    String materialSpec = VtuzxUtil.getString(doc, "materialSpec");
                    String unit = VtuzxUtil.getString(doc, "unit");
                    String remark = VtuzxUtil.getString(doc, "remark");
                    String prdType = VtuzxUtil.getString(doc, "prdType");
                    String sonBigType = VtuzxUtil.getString(doc, "sonBigType");
                    double SumCount = VtuzxUtil.getDouble(doc, "SumCount");
                    double money = VtuzxUtil.getDouble(doc, "money");
                    double costPrice = VtuzxUtil.getDouble(doc, "costPrice");
                    double avgPrice = VtuzxUtil.getDouble(doc, "avgPrice");
                    Document insert = new Document("billNo", mainBillNo)
                            .append("prdType", prdType)
                            .append("sonBigType", sonBigType)
                            .append("materialNo", materialNo)
                            .append("materialName", materialName)
                            .append("materialSpec", materialSpec)
                            .append("unit", unit)
                            .append("SumCount", SumCount)
                            .append("remark", remark)
                            .append("money", money)
                            .append("costPrice", costPrice)
                            .append("avgPrice", avgPrice)
                            .append("accountingPeriod", accountingPeriod)
                            .append("distributor", distributor)
                            .append("count", count)
                            .append("pickCount", 0)
                            .append("surplusCount", count)
                            .append("createUserName", name)
                            .append("createUserId", _userId);
                    insertList.add(insert);
                }
                distributorDetailDao.insertMany(insertList);

                Document mainDoc = new Document("billNo", mainBillNo)
                        .append("accountingPeriod", accountingPeriod)
                        .append("distributor", distributor)
                        .append("boxCount", boxCount)
                        .append("count", sum);
                distributorDao.insertBill(_userId, name, mainDoc);
            }

        });
    }

    @Override
    public VtuzxMap getjkySaleOut(ObjectId userId, Map<String, Object> param, int pageIndex, int pageSize) {
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String billNo = VtuzxUtil.getString(param, "billNo");
        String materialNo = VtuzxUtil.getString(param, "materialNo");
        String batchNo = VtuzxUtil.getString(param, "batchNo");
        String boxNo = VtuzxUtil.getString(param, "boxNo");
        List<VtuzxMap> dataList = new ArrayList<>();
        Criteria cond = new Criteria();
        cond.and("type").is("jikeyun");


        VtuzxPage page = saleOutDao.page(cond, new Document("createTime", -1), pageIndex, pageSize);
        dataList = page.iterator(doc -> new VtuzxMap("id", VtuzxUtil.getString(doc, IVtuzxConst.Key__id))
                .append("billNo", VtuzxUtil.getString(doc, "billNo"))
                .append("createUserName", VtuzxUtil.getString(doc, "createUserName"))
                .append("_createUserId", VtuzxUtil.getObject(doc, "_createUserId"))
                .append("boxCount", VtuzxUtil.getInt(doc, "boxCount"))
                .append("status", VtuzxUtil.getString(doc, "status"))
                .append("stockNo", VtuzxUtil.getString(doc, "stockNo"))
                .append("auditTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "auditTime")))
                .append("pickType",VtuzxUtil.getString(doc,"pickType"))
                .append("count", VtuzxUtil.getDouble(doc, "count")));
        return new VtuzxMap(IVtuzxConst.Key_total, page.total()).append(IVtuzxConst.Key_data, dataList);
    }

}
